﻿using System;
using System.Collections.Generic;

namespace CommandLineParser
{
    public class CommandLineParser
    {
        #region Public : Class Entry
        /// <summary>
        /// Run command line parse for this program arguements.
        /// </summary>
        public CommandLineParser() { this.RunCommandLineParser(); }
        /// <summary>
        /// Run command line parse with arguments.
        /// </summary>
        /// <param name="args">arguments.</param>
        public CommandLineParser(string[] args) { this.RunCommandLineParser(args); }
        #endregion

        #region Private : Class Globals 
        private List<CommandLineParsedData> CLPData = null;
        #endregion

        #region Public : Get Command Line Parse Data
        public CommandLineParsedData GetParsedDataByKey(string Key)
        {
            if(this.CLPData != null)
            {
                foreach(var pdata in this.CLPData)
                    if (pdata.Key == Key)
                        return pdata;
            }
            return null;
        }
        public string GetValue(string Key)
        {
            var pdata = this.GetParsedDataByKey(Key);
            return pdata == null ? null : pdata.Value;
        }
        public StringParser GetValue_SParser(string Key)
        {
            var pdata = this.GetParsedDataByKey(Key);
            return pdata == null ? null : pdata.ValueAs;
        }
        public class CommandLineParsedData
        {
            private string _key = null;
            private string _val = null;
            private StringParser _val_as = null;

            public string Key { get { return this._key; } }
            public string Value { get { return this._val; } }
            public StringParser ValueAs { get { if (this._val_as == null) { this._val_as = new StringParser(this._key); } return this._val_as; } }

            public CommandLineParsedData(string k, string v)
            {
                this._key = k;
                this._val = v;
                //this._val_as = new StringParser(v);
            }
        }
        public CommandLineParsedData[] ParsedData { get { return (this.CLPData != null && this.CLPData.Count > 0) ? this.CLPData.ToArray() : null; } }
        #endregion

        #region Private : CommandLineParser (Core); Data Parsing
        private void RunCommandLineParser(string[] args = null)
        {
            if (this.CLPData == null)
                this.CLPData = new List<CommandLineParsedData>();

            if (args == null)
                args = Environment.GetCommandLineArgs();

            if (args != null)
            {
                for (int i = 0; i < args.Length; i++)
                {
                    if (args[i].StartsWith("-") || args[i].StartsWith("/"))
                    {
                        var data = this.ParseData(args, i);
                        if(data != null)
                            this.SafeParsedDataAdd(data);
                    }
                }
            }
        }
        private CommandLineParsedData ParseData(string[] args, int index)
        {
            string my_key = null;
            string my_val = null;
            if (args[index].StartsWith("-") || args[index].StartsWith("/"))
            {
                if(args[index].Contains(":"))
                {
                    string argument = args[index];
                    //parse_key
                    int end_index = argument.IndexOf(':');
                    my_key = argument.Substring(0, end_index);
                    //parse_value
                    int value_start_index = end_index + 1;
                    my_val = value_start_index < argument.Length ? argument.Substring(value_start_index, argument.Length - value_start_index) : null;
                }
                else
                {
                    my_key = args[index];//keyvalue
                    int arg_index = 1 + index;
                    if (arg_index < args.Length && !(args[arg_index].StartsWith("-") || args[arg_index].StartsWith("/")))
                    {
                        my_val = args[arg_index];//key_value_found..
                    }
                    else
                    {
                        my_val = null;//doesn't contains key.
                    }
                }
            }

            return my_key != null ? new CommandLineParsedData(my_key, my_val) : null;
        }
        /// <summary>
        /// insure that key with the same name isn't already added if its already added then overwrite it.
        /// </summary>
        /// <param name="pData">command line parsed key</param>
        private void SafeParsedDataAdd(CommandLineParsedData pData)
        {
            if(pData.Key != null)
            {
                for(int i = 0; i < this.CLPData.Count; i++)
                {
                    if(this.CLPData[i].Key == pData.Key)
                    {
                        this.CLPData.RemoveAt(i);
                    }
                }
                this.CLPData.Add(pData);
            }
        }
        #endregion
    }
    /// <summary>
    /// String parser
    /// </summary>
    public class StringParser
    {
        private readonly string conversion_string = null;
        /// <summary>
        /// String Parser
        /// </summary>
        /// <param name="conv_str">conversion string</param>
        public StringParser(string conv_str)
        {
            this.conversion_string = conv_str;

            //----Set--Default--Values----//
            DefaultValues.INT = 0;
            DefaultValues.UINT = 0;
            DefaultValues.FLOAT = 0.0f;
            DefaultValues.DOUBLE = 0.0d;
            DefaultValues.BOOLEAN = false;
        }

        public static class DefaultValues
        {
            public static int INT { get; set; }
            public static uint UINT { get; set; }
            public static float FLOAT { get; set; }
            public static double DOUBLE { get; set; }
            public static bool BOOLEAN { get; set; }
        }

        /// <summary>
        /// String to be parsed.
        /// </summary>
        public string String 
        { 
            get 
            { 
                return this.conversion_string; 
            } 
        }

        /// <summary>
        /// Read as int.
        /// </summary>
        public int Int
        {
            get
            {
                int temp = 0;
                return int.TryParse(this.conversion_string, out temp) ? temp : DefaultValues.INT;
            }
        }

        /// <summary>
        /// Read as unsigned int.
        /// </summary>
        public uint UInt
        {
            get
            {
                uint temp = 0;
                return uint.TryParse(this.conversion_string, out temp) ? temp : DefaultValues.UINT;
            }
            
        }

        /// <summary>
        /// Read as Float.
        /// </summary>
        public float Float
        {
            get
            {
                float temp = 0;
                return float.TryParse(this.conversion_string, out temp) ? temp : DefaultValues.FLOAT;
            }
            
        }

        /// <summary>
        /// Read as Double.
        /// </summary>
        public double Double
        {
            get
            {
                double temp = 0;
                return double.TryParse(this.conversion_string, out temp) ? temp : DefaultValues.DOUBLE;
            }
        }

        /// <summary>
        /// Read as Boolean.
        /// </summary>
        public bool Boolean
        {
            get
            {
                bool temp = false;
                return bool.TryParse(this.conversion_string, out temp) ? temp : DefaultValues.BOOLEAN;
            }
        }
    }
}
